package com.inpion.model.board.helper;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

import com.inpion.model.board.AbstractBrokerModel;
import com.inpion.model.board.BoardConstant;
import com.inpion.model.board.ModelContainer;

public class BoardBuilder {
	
	private static final String COLLECTION_TYPE_BOARD_BOARD_ID = "//collection[@type='board']/board[@id='";
	private static SAXBuilder builder = new SAXBuilder();
    private static Document document = null;

    static{
    	loadConfigure();
    }
    
	public static ModelContainer build(String boardId) throws BoardIdNotFoundException {
		synchronized (boardId) {
			
			try {
				Element boardElement = (Element)XPath.selectSingleNode(document, COLLECTION_TYPE_BOARD_BOARD_ID + boardId + "']");
				
				if (boardElement == null){
					throw new BoardIdNotFoundException();
				}else{
					return buildBoardDetail(boardElement, boardId);
				}
			} catch (JDOMException e) {
				e.printStackTrace();
			}
			
		}
		
		return null;

	}

	private static ModelContainer buildBoardDetail(Element boardElement, String boardId) {
		
		String basePackage = boardElement.getAttributeValue(BoardConstant.BASE_PACKAGE);
		ModelContainer retContainer = new ModelContainer("default.board.container");
		retContainer.put(BoardConstant.BASE_PACKAGE, basePackage);
		
		buildBoardElement(retContainer, boardElement, basePackage);

		return retContainer;
	}

	@SuppressWarnings("unchecked")
	private static void buildBoardElement(AbstractBrokerModel boardObject, Element boardElement, String basePackage) {
		
		String idString = boardElement.getAttributeValue(BoardConstant.ID);
		String classNameString = boardElement.getAttributeValue(BoardConstant.CLASS_NAME);
		AbstractBrokerModel tgrObject = null;
		
		if (classNameString != null){
			
			try {
				
				classNameString = basePackage + "." + classNameString;
				Class<?> tgrClass = Class.forName(classNameString);
				Constructor<?> tgrConst = tgrClass.getConstructor(String.class);
				tgrObject = (AbstractBrokerModel) tgrConst.newInstance(idString);
				boardObject.put(boardElement.getName(), tgrObject);
				
				List<Element> childrenElement = boardElement.getChildren();
				
				for (Element tgrElement : childrenElement){
					buildBoardElement(tgrObject, tgrElement,  basePackage);
				}
				
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
			
		}else{
			boardObject.put(boardElement.getName(), boardElement.getValue());
		}
	}

	private static Document loadConfigure() {
		if (document == null){
			InputStream iStream = BoardBuilder.class.getResourceAsStream("/com/inpion/model/board/boardConfig.xml");
			try {
				document = builder.build(iStream);
			} catch (JDOMException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		return document;
	}

	
}
